package com.people.core.validator.util;

import ai.people.netmon.framework.exception.enums.ParamExceptionEnum;
import ai.people.netmon.framework.exception.type.MethodNotValidException;
import com.people.core.validator.factory.ValidatorFailFastFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.executable.ExecutableValidator;
import javax.validation.groups.Default;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;

/**
 * 参数校验器工厂
 *
 * @author yuanqinglong
 * @since 2021/2/26 17:31
 */
public class ValidatorUtils {

    /**
     * 快速失败校验器，有一个校验未通过直接返回错误 不在继续校验
     */
    private static ValidatorFailFastFactory validatorFailFast;

    /**
     * 返回全部的校验未通过错误提示
     */
    private static ValidatorFactory localValidatorFactoryBean;

    @Autowired
    public void setValidatorFailFast(ValidatorFailFastFactory validatorFailFast) {
        ValidatorUtils.validatorFailFast = validatorFailFast;
    }

    @Autowired
    public void setLocalValidatorFactoryBean(ValidatorFactory localValidatorFactoryBean) {
        ValidatorUtils.localValidatorFactoryBean = localValidatorFactoryBean;
    }

    /**
     * 错误信息的分隔符
     */
    private static final String DELIMITER = ";";

    public static Validator getValidatorFailFast() {
        return validatorFailFast.getValidator();
    }


    public static Validator getValidator() {
        return localValidatorFactoryBean.getValidator();
    }


    /**
     * 快速失败校验，获取校验方法单个参数的校验器
     *
     * @return 参数校验器
     */
    private static ExecutableValidator getExecutableFastFailValidator() {
        return getValidatorFailFast().forExecutables();
    }


    /**
     * 获取校验方法单个参数的校验器
     *
     * @return 参数校验器
     */
    private static ExecutableValidator getExecutableValidator() {
        return getValidator().forExecutables();
    }


    /**
     * 获取校验方法单个参数的校验器
     *
     * @param fastFail true 启用快速失败校验、false 校验全部
     * @return 参数校验器
     */
    public static ExecutableValidator getExecutableValidator(boolean fastFail) {
        return fastFail ? getExecutableFastFailValidator() : getExecutableValidator();
    }


    /**
     * 快速失败校验，有一个校验未通过直接返回错误
     *
     * @param o     参数
     * @param group 组
     */
    public static void fastFailValidator(Object o, Class<?>... group) {
        Set<ConstraintViolation<Object>> validate = getValidatorFailFast().validate(o, group);
        for (ConstraintViolation<Object> tConstraintViolation : validate) {
            String message = tConstraintViolation.getMessage();
            if (Objects.nonNull(message)) {
                throw new MethodNotValidException(message, ParamExceptionEnum.INSUFFICIENT_PARAMETERS.getCode());
            }
        }
    }

    /**
     * 验证器
     * 校验完全部字段返回所有未通过错误
     *
     * @param o     参数
     * @param group 组
     */
    public static void validator(Object o, Class<?>... group) {
        Set<ConstraintViolation<Object>> validate = getValidator().validate(o, group);
        String validResult2String = validResult2String(validate);
        if (Objects.nonNull(validResult2String)) {
            throw new MethodNotValidException(validResult2String,ParamExceptionEnum.INSUFFICIENT_PARAMETERS.getCode());
        }
    }


    /**
     * 校验完全部字段返回所有未通过错误
     *
     * @param o        参数
     * @param fastFail true 启用快速失败校验、false 校验全部
     * @param group    组
     */
    public static void validator(Object o, boolean fastFail, Class<?>... group) {
        if (fastFail) {
            fastFailValidator(o, group);
        } else {
            validator(o, group);
        }
    }


    /**
     * 校验完全部字段返回所有未通过错误
     *
     * @param o 参数
     */
    public static void fastFailValidator(Object o) {
        fastFailValidator(o, Default.class);
    }


    /**
     * 校验完全部字段返回所有未通过错误
     *
     * @param o 参数
     */
    public static void validator(Object o) {
        validator(o, Default.class);
    }

    /**
     * 转换集合为错误信息
     *
     * @param result 错误集合
     */
    public static String validResult2String(Set<ConstraintViolation<Object>> result) {
        if (CollectionUtils.isEmpty(result)) {
            return null;
        }

        StringJoiner stringJoiner = new StringJoiner(DELIMITER);
        for (ConstraintViolation<Object> tConstraintViolation : result) {
            stringJoiner.add(tConstraintViolation.getMessage());
        }
        return stringJoiner.toString();
    }


}
